<?php

namespace app\common\business\sendFcm;

use app\common\business\BaseBus;
use app\common\model\SendLog;
use app\common\model\SendMsg;
use Kreait\Firebase\Exception\MessagingException;
use Kreait\Firebase\Factory;
use Kreait\Firebase\Messaging\CloudMessage;
use Kreait\Firebase\Messaging\Notification;
use support\Log;

class FcmTopic extends BaseBus
{
    protected static $messaging;
    public function __construct()
    {
        $factory = (new Factory())->withServiceAccount(base_path().'/calm-segment-416609-56b780217794.json');
        self::$messaging = $factory->createMessaging();
    }

    /**
     * 订阅主题（将设备token添加到主题）
     * @param $token
     * @param $topicName
     * @return bool
     * @throws \think\db\exception\DbException
     */
    public static function subscribeToTopic($token,$topicName='') {
        $topicModel = new \app\common\model\Topics();
        if (empty($topicName)) {
            $topicName = env('SYSTEM_TOPIC');
        }
        $topic = $topicModel->getFindData(['topic' => $topicName], 'id,topic,nums', ['id'=>'desc']);

        $result = self::$messaging->subscribeToTopic($topicName, [$token]);
        if (!isset($result[$topicName]) || empty($result[$topicName])) {
            Log::error('订阅主题失败--error: '.json_encode($result, JSON_UNESCAPED_UNICODE));
            return false;
        }

        $userTopicModel = new \app\common\model\UserTopic();
        if (empty($topic)) {
            $topicRes = $topicModel->insertGetId(['topic' => $topicName, 'nums' => 1, 'created_at' => time()]);
            if ($topicRes) {
                $userTopicModel->insertGetId(['topic_id'=>$topicRes,'fcm_token'=>$token,'created_at' => time()]);
            }
        } else {
            $hasUserTopic = $userTopicModel->getFindData(['fcm_token'=>$token,'topic_id'=>$topic['id']]);
            if (empty($hasUserTopic)) {
                $topicRes = $topicModel->where(['id' => $topic['id'], 'nums' => $topic['nums']])
                    ->inc('nums')
                    ->update(['updated_at' => time()]);
                if ($topicRes) {
                    $userTopicModel->insertGetId(['topic_id'=>$topic['id'],'fcm_token'=>$token,'created_at' => time()]);
                }
            }
        }
        return true;
    }
    // 订阅的主题
    public static function getTopics($token)
    {
        $arr = [];
        try {
            $appInstance = self::$messaging->getAppInstance($token);
            $subscriptions = $appInstance->topicSubscriptions();
            $arr = [];
            foreach ($subscriptions as $subscription) {
                $arr[] = $subscription->topic();
            }
        } catch (\Exception $e) {
            Log::error('查询订阅主题失败-error:'.$e->getMessage().$e->getFile().$e->getLine());
        }
        return $arr;
    }

    /**
     * 取消订阅主题
     * @param $token // 用户token
     * @param $topicName // 主题
     * @param $type // 1=所有主题
     * @return bool
     * @throws MessagingException
     * @throws \support\exception\BusinessException
     * @throws \think\db\exception\DbException
     */
    public static function unSubscribeToTopic($token,$topicName='',$type=0)
    {
        if (empty($topicName)) {
            if ($type == 1) { // 所有主题
                $getTopics = self::getTopics($token);
            } else {
                $getTopics[] = env('SYSTEM_TOPIC');
            }
        } else {
            $getTopics = explode(',', $topicName);
        }

        $valiToken = self::valiTokenBus($token);
        if (empty($valiToken) || !isset($valiToken['rel']['topics'])) {
            return false;
        }
        foreach ($getTopics as $topic) {
            self::$messaging->unsubscribeFromTopic($topic, [$token]);
        }
//        if (!isset($result[$topicName]) || empty($result[$topicName])) {
//            Log::error('取消订阅主题失败--error: '.json_encode($result, JSON_UNESCAPED_UNICODE));
//            return false;
//        }
        $userTopicModel = new \app\common\model\UserTopic();
        $userTopicModel->where(['fcm_token'=>$token])->delete();

        return true;
    }

    /**
     * 给主题发送消息
     * @param $topic
     * @param $title
     * @param $content
     * @return bool
     * @throws \Kreait\Firebase\Exception\FirebaseException
     * @throws \support\exception\BusinessException
     */
    public static function sendTopicMsg($topic,$title,$content)
    {
        if (empty($topic)) {
            $topic = env('SYSTEM_TOPIC');
        }
        $message = CloudMessage::fromArray([
            'topic' => $topic,
            'notification' => ['title' => $title,'body' => $content],
            'data' => []
        ]);
        try {
            $res = self::$messaging->send($message);
            if (!isset($res['name']) || empty($res['name'])) {
                Log::error('sendTopicMsg-error:'.json_encode($res));
                return false;
            }
        } catch (MessagingException $e) {
            Log::error('sendTopicMsg-error:'.$e->getMessage().$e->getFile().$e->getLine());
            return false;
        }
        return true;
    }

    /**
     * 向某个设备推送消息
     * @param $token
     * @param $title
     * @param $content
     * @return bool
     * @throws \Kreait\Firebase\Exception\FirebaseException
     */
    public static function toDeviceMsg($user,$sendMsg=[])
    {
        // 查询最新的消息
        if (empty($sendMsg)) {
            $sendMsg = SendMsg::field('id,title,content')
                ->order(['id'=>'desc'])->find();
        }
        $title = $sendMsg['title'] ?? '你有一条新消息';
        $body = $sendMsg['content'] ?? '你有一条新消息';

        $message = CloudMessage::fromArray([
            'token' => $user['fcm_token'],
            'notification' => ['title' => $title,'body' => $body], // optional
            'data' => [], // optional
        ]);

        try {
            $result = self::$messaging->send($message);

            $sendLogData = [
                'msg_id' => $sendMsg['id'],
                'user_ids' => $user['id'],
                'created_at' => time()
            ];
            $hasLog = SendLog::field('id,user_ids')->where(['msg_id' => $sendMsg['id'], 'type' => 0])
                ->order(['id' => 'desc'])->find();

            if (isset($result['name']) && !empty($result['name'])) {

                if (empty($hasLog)) {
                    $logId = (new SendLog)->insertGetId($sendLogData);
                } else {
                    $saveData = [
                        'user_ids' => $hasLog['user_ids'] . ',' . $user['id'],
                        'updated_at' => time()
                    ];
                    SendLog::where(['id' => $hasLog['id']])->update($saveData);
                    $logId = $hasLog['id'];
                }
                return $logId;
            } else {
                if (!empty($hasLog)) {
                    $sendLogData['updated_at'] = time();
                    $sendLogData['error_msg'] = json_encode($result, JSON_UNESCAPED_UNICODE);
                    SendLog::where(['id' => $hasLog['id']])->update($sendLogData);
                }
                \support\Log::error('发送消息失败-error:' . json_encode($result, JSON_UNESCAPED_UNICODE));
            }
        } catch (\Exception $e) {
            Log::error('推送消息失败-error:'.$e->getMessage());
            return false;
        }
        return false;
    }

    /**
     * 获取token所有信息
     * @param $token
     * @return mixed[]
     * @throws MessagingException
     * @throws \support\exception\BusinessException
     */
    public static function valiTokenBus($token)
    {
        try {
            $getAppInstance = self::$messaging->getAppInstance($token);
            return $getAppInstance->rawData();
        } catch (MessagingException $e) {
            Log::error('valiTokenBus-error:'.$e->getMessage());
        }
        return false;
    }

    /**
     * 定时任务,是否还有订阅主题
     * @return bool
     * @throws MessagingException
     * @throws \think\db\exception\DbException
     */
    public static function checkTokenForTopicBus()
    {
        $userTopicModel = new \app\common\model\UserTopic();

        $userTopics = $userTopicModel->cursor();

        $factory = (new Factory())->withServiceAccount(base_path().'/calm-segment-416609-56b780217794.json');
        $messaging = $factory->createMessaging();
        if ($userTopics) {
            foreach ($userTopics as $userTopic) {
                $arr = [];
                try {
                    $appInstance = $messaging->getAppInstance($userTopic->fcm_token);
                    $subscriptions = $appInstance->topicSubscriptions();
                    $arr = [];
                    foreach ($subscriptions as $subscription) {
                        $arr[] = $subscription->topic();
                    }
                } catch (\Exception $e) {
                    Log::error('查询订阅主题失败-error:' . $e->getMessage() . $e->getFile() . $e->getLine());
                }
                if (empty($arr)) {
                    $userTopicModel->where('id', $userTopic->id)->delete();
                }
            }
        }
        return true;
    }

    /**
     * 定时任务,查询toekn是否有效
     * @return bool
     * @throws \think\db\exception\DbException
     */
    public static function checkToken()
    {
        $fcmTokenModel = new \app\common\model\UserFcmToken();
        $fcmTokens = $fcmTokenModel->cursor();

        $fcmMsgBus = new \app\common\business\sendFcm\FcmMessage();
        $accessToken = $fcmMsgBus::getFirebaseAccessToken();

        if ($fcmTokens) {
            foreach ($fcmTokens as $fcmToken) {
                // 验证token是否有效
                $vidToken = $fcmMsgBus::validateFcmToken($accessToken, $fcmToken['fcm_token']);
                if (isset($vidToken['isValid']) && empty($vidToken['isValid'])) {
                    $fcmTokenModel->where(['id' => $fcmToken['id']])->delete();

                    self::unSubscribeToTopic($fcmToken, '', 1);
                }
            }
        }
        return true;
    }
}
